package com.wulis.provider.authority.service.impl;

import static com.wulis.common.constant.GlobalConstant.ADMINISTRATOR;
import static com.wulis.common.model.enums.HttpStatusEnum.ILLEGAL_ARGUMENT;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wulis.common.exception.BusinessException;
import com.wulis.common.model.enums.DeletedStateEnum;
import com.wulis.common.support.BaseServiceImpl;
import com.wulis.common.utils.AuthUserUtil;
import com.wulis.common.utils.NodeUtil;
import com.wulis.config.security.AuthUserDetails;
import com.wulis.provider.authority.annotation.RoleChange;
import com.wulis.provider.authority.mapper.MenuMapper;
import com.wulis.provider.authority.model.dto.InsertMenuDto;
import com.wulis.provider.authority.model.dto.QueryMenuTreeDto;
import com.wulis.provider.authority.model.dto.UpdateMenuDto;
import com.wulis.provider.authority.model.entity.Menu;
import com.wulis.provider.authority.model.vo.InsertMenuVo;
import com.wulis.provider.authority.model.vo.QueryMenuTreeVo;
import com.wulis.provider.authority.model.vo.QueryMenuVo;
import com.wulis.provider.authority.service.MenuService;

import lombok.AllArgsConstructor;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;

/**
 * 权限管理:菜单表 Service实现类
 *
 * @author WuliBao
 * @date 2020-04-17
 */
@Slf4j
@Service
@AllArgsConstructor
public class MenuServiceImpl extends BaseServiceImpl<MenuMapper, Menu> implements MenuService {
    
    private final MenuMapper menuMapper;
    
    /**
     * WEB:查询菜单树
     *
     * @param queryMenuTreeDto queryMenuTreeDto
     * @return List
     */
    @Override
    public List<QueryMenuTreeVo> queryMenuTree(@NonNull QueryMenuTreeDto queryMenuTreeDto) {
        // 查询菜单列表
        List<QueryMenuTreeVo> menuList =
            menuMapper.queryMenuList(queryMenuTreeDto.getMenuName(), queryMenuTreeDto.getEnable());
        return NodeUtil.buildTree(menuList);
    }
    
    /**
     * WEB:查询菜单列表（当前登录用户）
     *
     * @return List<MenuVo>
     */
    @Override
    public List<QueryMenuTreeVo> queryMenuList() {
        AuthUserDetails authUserDetails = AuthUserUtil.getDetails();
        // 如果是超级管理员账号，查询所有菜单
        if (ADMINISTRATOR.equals(authUserDetails.getAccountId())) {
            return menuMapper.queryMenuList(null, null);
        }
        // 根据账号角色查询菜单
        List<Long> roleIds =
            authUserDetails.getRoles().stream().map(AuthUserDetails.Role::getRoleId).collect(Collectors.toList());
        if (roleIds.isEmpty()) {
            return new ArrayList<>();
        }
        // 查询菜单列表
        return menuMapper.queryMenuListByRoleIds(roleIds);
    }
    
    /**
     * WEB:查询菜单
     *
     * @param id id
     * @return QueryMenuVo
     */
    @Override
    public QueryMenuVo queryMenu(@NonNull Long id) {
        Menu menu = menuMapper.selectById(id);
        if (menu == null) {
            return null;
        }
        QueryMenuVo queryMenuVo = new QueryMenuVo();
        BeanUtils.copyProperties(menu, queryMenuVo);
        return queryMenuVo;
    }
    
    /**
     * WEB:新增菜单
     * 
     * @param insertMenuDto insertMenuDto
     * @return InsertMenuVo
     */
    @Override
    @RoleChange
    @Transactional(rollbackFor = Exception.class)
    public InsertMenuVo insertMenu(@NonNull InsertMenuDto insertMenuDto) {
        // 默认的父级IDS
        String parentIds = "/";
        // 新增菜单
        Menu menu = new Menu().setParentIds(parentIds);
        BeanUtils.copyProperties(insertMenuDto, menu);
        // 查询父级菜单
        if (insertMenuDto.getParentId() != null) {
            Menu parentMenu = menuMapper.selectById(insertMenuDto.getParentId());
            if (parentMenu != null) {
                parentIds = parentMenu.getParentIds() + parentMenu.getId() + parentIds;
            }
            else {
                throw new BusinessException(ILLEGAL_ARGUMENT);
            }
        }
        else {
            menu.setParentId(0L);
            parentIds = parentIds + 0L + parentIds;
        }
        menu.setParentIds(parentIds);
        menuMapper.insert(menu);
        // 返回插入的菜单
        InsertMenuVo insertMenuVo = new InsertMenuVo();
        BeanUtils.copyProperties(menu, insertMenuVo);
        return insertMenuVo;
    }
    
    /**
     * WEB:修改菜单
     * 
     * @param updateMenuDto updateMenuDto
     * @return UpdateMenuVo
     */
    @Override
    @RoleChange
    @Transactional(rollbackFor = Exception.class)
    public Integer updateMenu(@NonNull UpdateMenuDto updateMenuDto) {
        // 默认的父级IDS
        String parentIds = "/";
        Menu menu = new Menu();
        BeanUtils.copyProperties(updateMenuDto, menu);
        // 查询父级菜单
        if (updateMenuDto.getParentId() != null) {
            Menu parentMenu = menuMapper.selectById(updateMenuDto.getParentId());
            if (parentMenu == null) {
                throw new BusinessException(ILLEGAL_ARGUMENT);
            }
            else {
                parentIds = parentMenu.getParentIds() + parentMenu.getId() + parentIds;
            }
        }
        else {
            menu.setParentId(0L);
            parentIds = parentIds + 0L + parentIds;
        }
        // 查询未修改前的子节点parentIds
        Menu oldMenu = menuMapper.selectById(updateMenuDto.getId());
        String oldParentIds = oldMenu.getParentIds() + oldMenu.getId() + "/";
        // 修改菜单
        menu.setParentIds(parentIds);
        int update = menuMapper.updateById(menu);
        // 修改后的parentIds
        String newParentIds = menu.getParentIds() + menu.getId() + "/";
        // 修改下级菜单的parentIds
        menuMapper.updateChildMenu(oldParentIds, newParentIds);
        return update;
    }
    
    /**
     * WEB:删除菜单
     * 
     * @param menuId menuId
     * @return Integer
     */
    @Override
    @RoleChange
    @Transactional(rollbackFor = Exception.class)
    public Integer deleteMenu(@NonNull Long menuId) {
        // 删除菜单及下级菜单(逻辑删除)
        QueryWrapper<Menu> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Menu::getId, menuId).or().like(Menu::getParentIds, "/" + menuId + "/");
        Menu menu = new Menu();
        menu.setDeleted(DeletedStateEnum.IS_DELETED.value());
        return menuMapper.update(menu, queryWrapper);
    }
}
